# _*_coding:utf-8_*_
"""
    Base prober driver define. All other prober driver should inherit from this class.
    Developed by Ivy.Li 2013.03.27.
   (C)Copyright 2013 Hech. All rights reserved
"""

#######NOTE for define Prover driver operation return value########
# if prober error can be ignored, please define return value in [20001,22000]
# if prober fatal error occured, please define return value in [25001,26000]
# Prober operation type define for semiconductor field
import os
import sys
import time
from ATS.util import constant
from ATS.globaldata import gdata
from ATS.communication import pyvisaImpl
workpath = os.path.dirname(os.path.realpath(sys.argv[0]))
sys.path.insert(0, os.path.dirname(workpath))


PR_INIT = 500
PR_MOVE = 501
PR_RELMOVE = 502
PR_RELRETURN = 503
PR_CHUCK = 504
PR_LOAD = 505
PR_UNLOAD = 506
PR_INK = 507

# define prober related fail error
PrInitFail = 21803
PrMoveFail = 21804
PrChuckFail = 21805
PrInkFail = 21806
PrLoadFail = 21807
PrUnLoadFail = 21808
# Prober type define
FAKE_PROBER = 0
HECH_PROBER = 1

NO_ERR = 0

PROBER_OBJ = None  ## For ATS, there is only one prober connection object.

VISA_OBJ = None  ## communication visa object, there is only 1 connection object for 1 prober.

##use prober type
PROBER_TYPE = HECH_PROBER  # default as FAKE prober
PROBER_ADDR = 5
GPIB_CARDNUM = 'GPIB1'


def set_prb_info(info_dict):
    """
    PROBER_TYPE: FAKE or HECH is supported now. 2013/11/30
    info_dict{
    model: HECH or FAKE
    prober_addr: prober address
    }
    """
    global PROBER_TYPE
    global PROBER_ADDR
    global GPIB_CARDNUM

    model = info_dict.get('model', 'FAKE')
    if model == 'FAKE':
        PROBER_TYPE = FAKE_PROBER
    elif model == 'HECH':
        PROBER_TYPE = HECH_PROBER
    else:
        PROBER_TYPE = FAKE_PROBER

    addr = info_dict.get('prober_addr', '')

    if addr:
        PROBER_ADDR = addr

    card_num = info_dict.get('GPIB_CARDNUM'.lower(), '0')
    global GPIB_CARDNUM
    GPIB_CARDNUM = "GPIB%s" % card_num
    if not constant.build:
        print('PROBER_TYPE,PROBER_ADDR,GPIB_CARDNUM=', PROBER_TYPE, PROBER_ADDR, GPIB_CARDNUM)


def ProberFactory():
    global PROBER_OBJ
    global PROBER_TYPE

    if PROBER_OBJ is not None:
        return PROBER_OBJ

    if PROBER_TYPE == FAKE_PROBER:
        PROBER_OBJ = BaseProber()
    elif PROBER_TYPE == HECH_PROBER:
        PROBER_OBJ = WangProber()
    ##TO add branch here for different prober
    return PROBER_OBJ


class BaseProber:
    def __init__(self, type=FAKE_PROBER):
        self.type = type

    def dispatch_fun(self, Prb_opt, *args):
        # print("dispatch_fun Prb_opt %s"%str(Prb_opt))
        if Prb_opt == PR_INIT:
            return self.PrInit(*args)
        elif Prb_opt == PR_MOVE:
            return self.PrMove(*args)
        elif Prb_opt == PR_RELMOVE:
            return self.PrRelMove(*args)
        elif Prb_opt == PR_RELRETURN:
            return self.PrRelReturn(*args)
        elif Prb_opt == PR_CHUCK:
            return self.PrChuck(*args)
        elif Prb_opt == PR_LOAD:
            return self.PrLoad(*args)
        elif Prb_opt == PR_UNLOAD:
            return self.PrUnload(*args)

    def PrInit(self, *args):
        if not constant.build:
            print('Fake PrInit:%s' % str(args))
        return NO_ERR

    def PrMove(self, *args):
        if not constant.build:
            print('Fake PrMove:%s' % str(args))
        return NO_ERR

    def PrRelMove(self, *args):
        if not constant.build:
            print('Fake PrRelMove:%s' % str(args))
        return NO_ERR

    def PrRelReturn(self, *args):
        if not constant.build:
            print('Fake PrRelReturn')
        return NO_ERR

    def PrChuck(self, *args):
        if not constant.build:
            print('Fake PrChuck:%s' % str(args))
        return NO_ERR

    def PrLoad(self, *args):
        if not constant.build:
            print('Fake PrLoad')
        return NO_ERR

    def PrUnload(self, *args):
        if not constant.build:
            print('Fake PrUnload')
        return NO_ERR

    def PrInk(self, *args):
        if not constant.build:
            print('Fake PrInk')


class WangProber(BaseProber):
    def __init__(self, type=HECH_PROBER):
        # print("wangprob init function")
        BaseProber.__init__(self)
        self.type = type

    def transfer_data(self, n):
        if n >= 0:
            if n > 9:
                s1 = "+%s" % n
            else:
                s1 = "+0%s" % n
        else:
            if n > -10:
                s1 = "-0%s" % abs(n)
            else:
                s1 = "-%s" % abs(n)
        return s1

    def get_visa_obj(self):
        global VISA_OBJ
        global PROBER_ADDR
        global GPIB_CARDNUM

        if VISA_OBJ is None:
            VISA_OBJ = pyvisaImpl.PyvisaImpl(type='RS232', addr="com1", card=9600)
        #            VISA_OBJ=pyvisaImpl.pyvisaImpl(type='RS232',addr=PROBER_ADDR,card=GPIB_CARDNUM)

        VISA_OBJ.set_timeout(1000)
        return VISA_OBJ

    def PrInit(self, *args):
        return NO_ERR

    def PrMove(self, *args):
        if not constant.build:
            print(type(args[0]))

        visa_obj = self.get_visa_obj()
        args1 = self.transfer_data(args[0])
        args2 = self.transfer_data(args[1])

        site = {"curr_site": [args1, args2]}
        gdata.updateGDD(site)
        # status=visa_obj.write('PRMOVE<%s<%s<01>'%(args1,args2))
        # status=visa_obj.write(' ')

        # print('PRMOVE<%s<%s<move>'%(args1,args2))
        # print(site)

        # status=visa_obj.write('PRMOVE<+00<+00<01>')
        # if status==pyvisaImpl.TIMEOUT:
        #    return status
        #
        #        status=visa_obj.wait_for_srq()
        #        if status==pyvisaImpl.TIMEOUT:
        #            return status
        #        print('wait_for_srq return:',status)
        # t1=time.time()
        # status=visa_obj.read() # read is blocked read function!

        """
        while(1):
            time.sleep(1)
            n = visa_obj.inWaiting()
            print("move lenth is",n)
            if (n>1):
                status=visa_obj.rs_read(n)
                print(status)
                if("PRMOVE_OK" in status):
                    print("PRMOVE_OK ok")
                    break
        """

        if not constant.build:
            # print('PrMove visa read:',status,'cost time:',time.time()-t1)

            # if("PRMOVE_OK" in status):
            return NO_ERR
        else:
            return PrMoveFail

    def PrRelMove(self, *args):
        if not constant.build:
            print('Fake PrRelMove:%s' % str(args))
        visa_obj = self.get_visa_obj()
        args1 = self.transfer_data(args[0])
        args2 = self.transfer_data(args[1])
        # global_list = gdata.getGDD()
        # print(global_list)
        site = gdata.getGDD()['curr_site']
        # print(site)
        status = visa_obj.write('PRMOVE<%s<%s<%s>' % (site[0], site[1], args2))
        # print('PRMOVE<%s<%s<%s>'%(site[0],site[1],args2))
        # status=visa_obj.write('PRMOVE<+00<+00<01>')
        if status == pyvisaImpl.TIMEOUT:
            return status
        #
        #        status=visa_obj.wait_for_srq()
        #        if status==pyvisaImpl.TIMEOUT:
        #            return status
        #        print('wait_for_srq return:',status)
        t1 = time.time()
        # status=visa_obj.read() # read is blocked read function!
        while 1:
            time.sleep(1)
            n = visa_obj.inWaiting()
            # print("move lenth is",n)
            if n > 1:
                status = visa_obj.rs_read(n)
                # print(status)
                if "PRMOVE_OK" in status:
                    # print("PRMOVE_OK ok")
                    break
        if not constant.build:
            print('PrMove visa read:', status, 'cost time:', time.time() - t1)
        if "PRMOVE_OK" in status:
            return NO_ERR
        else:
            return PrMoveFail

    def PrChuck(self, *args):
        if not constant.build:
            print('Wang Prober  PrChuck:%s' % str(args))
        visa_obj = self.get_visa_obj()
        # print('Wang Prober  PrChuck')
        status = visa_obj.write('PRCHUCK>')
        if status == pyvisaImpl.TIMEOUT:
            return status
        while 1:
            time.sleep(1)
            n = visa_obj.inWaiting()
            # print("PrChuck lenth is",n)
            if n > 1:
                status = visa_obj.rs_read(n)
                # print(status)
                if "PRCHUCK_OK" in status:
                    # print("PRCHUCK ok")
                    break

        if not constant.build:
            print('Prchuck visa read:', status)
        if "PRCHUCK_OK" in status:
            return NO_ERR
        else:
            return PrChuckFail

    # INKING function

    def PrInk(self, *args):
        if not constant.build:
            print('Wang Prober  PrInk')

        visa_obj = self.get_visa_obj()
        status = visa_obj.write('PrInk()')
        if status == pyvisaImpl.TIMEOUT:
            return status

        status = visa_obj.read()
        #        print('visa read:',status)
        if status == 'true':
            return NO_ERR
        else:
            return PrInkFail

    def PrLoad(self, *args):
        # print("PrLoad args is ++++++++++++++++++++++")
        # print(args)
        map = []
        map_position = []
        m = 0
        num = 0
        # load a wafer to the chuck
        if not constant.build:
            print('PrLoad wang')

        visa_obj = self.get_visa_obj()

        globaldirt = gdata.getGDD()
        # print("globaldirt is ",globaldirt)
        # if globaldirt.has_key('MAP')==0:
        if globaldirt['First_wafer'] == 0:
            visa_obj.com_cls()
            status = visa_obj.write('PRINIT>')
            if status == pyvisaImpl.TIMEOUT:
                return status
            while 1:
                time.sleep(2)
                n = visa_obj.inWaiting()
                # print("lenth1 is")
                # print(n)
                if n > 1:
                    status = visa_obj.rs_read(n)
                    # print(status)
                    if "ProbeInit_OK" in status:
                        # print("INIT ok")
                        break
            # Read the wafer map
            visa_obj.com_cls()
            status = visa_obj.write('PRMAP>')
            if status == pyvisaImpl.TIMEOUT:
                return status
            while 1:

                time.sleep(2)
                n = visa_obj.inWaiting()
                # print("lenth2 is",n)
                if n > 1:
                    status = visa_obj.rs_read(n)
                    for i in status:
                        map.append(i)
                        m += 1
                        if (i == '1') or (i == '2') or (i == '4'):
                            num += 1
                            map_position.append(m)

                    wmap = {"MAP": map}

                    wafer_position = {"wafer_position": map_position}
                    wafer_num = {'wafer_num': num}

                    gdata.updateGDD(wmap)
                    gdata.updateGDD(wafer_position)
                    gdata.updateGDD(wafer_num)
                    gdata.updateGDD({'First_wafer': 1})  # set the sign to 1,means is not the first wafer
                    # print("wmap is",  wmap)
                    break
        # print(globaldirt)
        num = globaldirt["wafer_num"]
        map_position = globaldirt["wafer_position"]

        # print("map_position is ")
        # print(map_position)
        # print('wafer number is:%s'%num)
        if num:
            num -= 1
            wafer_num = {'wafer_num': num}
            gdata.updateGDD(wafer_num)

        str1 = 'PRLOAD%s>' % (map_position[num])
        status = visa_obj.write(str1)
        # print(str1)
        if status == pyvisaImpl.TIMEOUT:
            return status
        while 1:
            time.sleep(2)
            n = visa_obj.inWaiting()
            # print("lenth3 is",n)
            if n > 1:
                status = visa_obj.rs_read(n)
                # print(status)
                if "PROBE_FDAlign_OK" in status:
                    # print("PROBE_FDAlign_OK")
                    break
        if "PROBE_FDAlign_OK" in status:
            # print("PrLoad NO_ERR")
            return NO_ERR
        else:
            print("PrLoad ", status)
            return PrLoadFail

    def PrUnload(self, *args):
        if not constant.build:
            print('Fake PrLoad')
        visa_obj = self.get_visa_obj()
        globaldirt = gdata.getGDD()
        num = globaldirt["wafer_num"]
        map_position = globaldirt["wafer_position"]
        str1 = 'PRUNLOAD%s>' % (map_position[num])
        # str1 ='PRUNLOAD%s>'%str(1)
        status = visa_obj.write(str1)
        # print(str1)
        if status == pyvisaImpl.TIMEOUT:
            return status
        while 1:
            time.sleep(2)
            n = visa_obj.inWaiting()
            # print("UNLOAD lenth is",n)
            if n > 1:
                status = visa_obj.rs_read(n)
                # print(status)
                if "PRUNLOAD_OK" in status:
                    # print("PRUNLOAD_OK")
                    break
        if "PRUNLOAD_OK" in status:
            # print("PRUNLOAD_OK NO_ERR")
            return NO_ERR
        else:
            # print("PRUNLOAD_OK ",status)
            return PrLoadFail
